# -*- coding: utf-8 -*-

# File Name： class_find
# Description :
# Author : 'li'
# date： 2022/5/23
# Change Activity: 2022/5/23
import os.path
import re

from .file_util import try_read_file_text
from .path import list_file_paths_in_dir, join_relative_path, get_absolute_project_path


class ClassFinder:
    """
    通过正则匹配的方式查找类所在的py文件
    """

    def __init__(self, dir_lst=None):
        """
        带查找的文件夹范围

        Args:
            dir_lst:
        """
        self.dir_lst = dir_lst if dir_lst is not None else []
        assert isinstance(self.dir_lst, list)
        self.included_py_paths = self._load_py_included_py_paths()
        assert len(self.included_py_paths) > 0, 'ClassFinder does not contain any .py file.'
        self.class_path_mapping = self._load_class_path_mapping()

    def _load_py_included_py_paths(self):
        """
        把所有self.dir_lst 内的py文件找出来
        Returns:
            py文件list
        """

        path_lst = []
        for d in self.dir_lst:
            paths = list_file_paths_in_dir(join_relative_path(d), '.py')
            path_lst = paths + path_lst
        return path_lst

    @staticmethod
    def _get_class_name(content):
        """
        读取py文件,加载类名

        Args:
            content:

        Returns:

        """
        return re.findall(r"class\s+(\w+)", content)

    def _load_class_path_mapping(self):
        """
        加载类名和文件相对路径映射

        Returns:
            dict
        """
        mapping = {}
        for path in self.included_py_paths:
            content = try_read_file_text(path)
            class_names = ClassFinder._get_class_name(content)
            for name in class_names:
                if name in mapping:
                    error_content = f"class {name} 已经被定义，无法建立映射关系。"
                    raise Exception(error_content)
                relative_path = os.path.relpath(path, get_absolute_project_path())
                mapping[name] = relative_path
        return mapping

    def find_class_path(self, class_name):
        """
        通过类名查找对应的文件相对路径

        Args:
            class_name:

        Returns:

        """
        if class_name not in self.class_path_mapping:
            return None
        return self.class_path_mapping[class_name]
